package cate.game.activity.base.core;

import cate.game.GameBody;
import cate.game.activity.config.ActivityBaseCfgPO;
import cate.game.framework.ModuleMan;
import cp.solution.ops.status.ModOprStatus;
import lombok.Getter;
import lombok.Setter;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Optional;

public abstract class ActivityHandler<G extends ActivityGlobalData, S extends RoleActivitySingle> extends ModuleMan {
    @Getter
    @Setter
    private int funcId;
    @Getter
    @Setter
    private G globalData;
    private long checkTime;

    @Getter
    private Type globalType;
    @Getter
    private Type singleType;

    public ActivityHandler() {
        Class<?> clazz = getClass();
        ParameterizedType superClass = (ParameterizedType) clazz.getGenericSuperclass();
        Type[] args = superClass.getActualTypeArguments();
        try {
            globalType = args[0];
            singleType = args[1];
        } catch (Exception e) {
            log.error("[ActivityHandler] 泛型解析错误: " + clazz.getName());
        }
    }

    @Override
    public final void initDependent() throws Exception {
        // 原则上这个接口不会被调用
    }

    /**
     * 活动名称
     */
    public abstract String getName();

    /**
     * 构建全服数据
     */
    public abstract G buildGlobal();

    /**
     * 构建个人数据
     */
    public abstract S buildSingle();

    /**
     * 装配全服数据
     *
     * @param funcId     功能ID
     * @param globalData 全服数据
     * @return 装配成功则返回值未空 装备失败则返回新建的全服数据
     */
    @SuppressWarnings("unchecked")
    public ActivityGlobalData setup(int funcId, ActivityGlobalData globalData) {
        setFuncId(funcId);
        try {
            if (!globalType.equals(globalData.getClass())) {
                log.warn("[" + getClass().getName() + "] 活动改变了全服数据类型! {} -> {}",
                        globalData.getClass().getName(), globalType.getTypeName());
                G newData = buildGlobal();
                newData.init(funcId);
                setGlobalData(newData);
                return newData;
            } else {
                setGlobalData((G) globalData);
                return null;
            }
        } catch (Exception e) {
            log.error("", e);
            return null;
        } finally {
            checkTime = Optional.ofNullable(globalData).map(gd -> gd.base.endTime).orElse(0L);
        }
    }

    /**
     * 初始化
     *
     * @param game 游戏本体
     */
    public void initialize(GameBody game) throws Exception {
        initIndependent(game);
        globalData.initialize();
    }

    /**
     * 设置新的时间配置
     *
     * @param currentCfg 新的时间配置
     */
    public final boolean setActivityConf(ActivityBaseCfgPO currentCfg) {
        if (currentCfg.eq(globalData.base)) {
            return globalData.base.readTime(currentCfg);
        }
        if (globalData.base.active()) {
            recordClose();
            close();
        }
        if (currentCfg.active()) {
            globalData.base = currentCfg;
        } else {
            globalData.base = ActivityBaseCfgPO.EMPTY(funcId);
        }
        if (globalData.base.active()) {
            recordOpen();
            open();
        }
        return false;
    }

    /**
     * 重置检测时间
     */
    public final void resetCheckTime() {
        if (globalData.base.active()) {
            checkTime = globalData.base.endTime;
        } else {
            checkTime = Optional.ofNullable(game.activityGlobal.loadComingActivityConfig(funcId))
                    .map(po -> po.startTime).orElse(0L);
        }
    }

    /**
     * 循环
     */
    public final void tick() {
        if (globalData.base.active()) {
            try {
                tickSelf();
            } catch (Exception e) {
                log.error("", e);
            }
        }
        if (checkTime == 0 || game.time.now() < checkTime) {
            return;
        }
        ActivityBaseCfgPO newConf = game.activityGlobal.loadOpeningActivityConfig(funcId);
        if (setActivityConf(newConf)) {
            resetCheckTime();
            game.role.activeForOnline(role -> role.getActivity().getActivitySingle(funcId).loadBase(false));
        }
    }

    /**
     * 活动自助循环
     */
    public void tickSelf() {

    }

    /**
     * 活动开启
     */
    public final void open() {
        onActOpen();
        game.role.activeForOnline(role -> {
            RoleActivitySingle single = role.getActivity().getActivitySingle(funcId);
            if (single != null) {
                single.loadBase(false);
            }
        });
    }

    /**
     * 活动开启逻辑实现
     * 原则上早于玩家逻辑
     */
    public abstract void onActOpen();

    /**
     * 活动关闭
     */
    public final void close() {
        onActClose();
        game.role.activeForOnline(role -> {
            RoleActivitySingle single = role.getActivity().getActivitySingle(funcId);
            if (single != null) {
                single.loadBase(false);
            }
        });
        globalData.clear();
    }

    /**
     * 活动关闭逻辑实现
     * 原则上早于玩家逻辑
     */
    public abstract void onActClose();

    /**
     * 记录活动开启
     */
    private void recordOpen() {
        log.info("[{}]的一个活动开始了,功能id:{} 活动id:{}",
                getName(), globalData.base.funcId, globalData.base.activityId);
    }

    /**
     * 记录活动结束
     */
    private void recordClose() {
        log.info("[{}]的一个活动结束了,功能id:{} 活动id:{}",
                getName(), globalData.base.funcId, globalData.base.activityId);
    }

    public int configTid() {
        return globalData.base.configTid;
    }

    @Override
    public ModOprStatus handleMergeSettle() {
        ModOprStatus status = new ModOprStatus(this.getName());
        onActClose();
        return status;
    }
}
